package com.ev.hr.service.impl;

import cn.afterturn.easypoi.entity.vo.TemplateExcelConstants;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.view.PoiBaseView;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ev.apis.model.DsResultResponse;
import com.ev.common.enums.AuditStatusDict;
import com.ev.common.vo.CustomizedColumnVO;
import com.ev.framework.config.MyExcelExportStyleConfig;
import com.ev.framework.il8n.MessageSourceHandler;
import com.ev.framework.utils.*;
import com.ev.hr.dao.SalaryAccountingDao;
import com.ev.hr.dao.SalaryArchivesDao;
import com.ev.hr.dao.SalaryProjectDao;
import com.ev.hr.domain.EmployeeInfoDO;
import com.ev.hr.domain.SalaryAccountingDO;
import com.ev.hr.domain.SalaryArchivesDO;
import com.ev.hr.enums.EnumForSalaryArchivesHeader;
import com.ev.hr.enums.EnumForSalaryProjectHeader;
import com.ev.hr.enums.SalaryProjectDict;
import com.ev.hr.service.EmployeeInfoService;
import com.ev.hr.service.GenerateExcelService;
import com.ev.hr.service.SalaryAccountingService;
import com.ev.hr.service.SalaryArchivesService;
import com.ev.hr.vo.SalaryAccountingPageParam;
import com.ev.hr.vo.SalaryArchivesPageParam;
import com.ev.hr.vo.SalaryProjectParam;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import javassist.CannotCompileException;
import javassist.NotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.ModelMap;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GenerateExcelServiceImpl implements GenerateExcelService {
    @Autowired
    private SalaryProjectDao salaryProjectDao;
    @Autowired
    private SalaryArchivesService salaryArchivesService;
    @Autowired
    private EmployeeInfoService employeeInfoService;
    @Autowired
    private SalaryArchivesDao salaryArchivesDao;
    @Autowired
    private SalaryAccountingService salaryAccountingService;
    @Autowired
    private SalaryAccountingDao salaryAccountingDao;
//    @Autowired
//    private SalaryChangeDao salaryChangeDao;
    @Autowired
    private MessageSourceHandler messageSourceHandler;

    @Override
    public void downLoadSalaryArchives(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap, boolean isData) {

        try {
            List<ExcelExportEntity> colList = new ArrayList<>();
            SalaryProjectParam salaryProjectParam = new SalaryProjectParam();
            salaryProjectParam.setAttribute(SalaryProjectDict.FIXED.getId());
            List<Map<String, Object>> projectList = salaryProjectDao.getProjectList(salaryProjectParam);
            projectList.sort(Comparator.comparing(e -> Integer.parseInt(e.get("sortNo").toString())));
            ExcelExportEntity colEntity;
            List<Map<String, Object>> list = Lists.newArrayList();
            Map<String, Object> valMap = Maps.newHashMap();

            // 表头
            LinkedHashMap<String, String> propertyToLabel = EnumForSalaryArchivesHeader.getPropertyToLabel();
            boolean isFirst = true;
            for (Map.Entry<String, String> stringStringEntry : propertyToLabel.entrySet()) {
                String property = stringStringEntry.getKey();
                colEntity = new ExcelExportEntity(stringStringEntry.getValue(), property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
                if (isFirst) {
                    valMap.put(stringStringEntry.getKey(), "{{$fe:list t." + stringStringEntry.getKey());
                    isFirst = false;
                    continue;
                }
                valMap.put(property, "t." + property);
            }

            // 表中
//            int size = projectList.size();
            for (Map<String, Object> map : projectList) {
                String label = map.get("label").toString();
                String property = map.get("property").toString();
                colEntity = new ExcelExportEntity(label, property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
//                if (i == 0) {
//                    valMap.put(property, "{{$fe:list t." + property);
//                    continue;
//                }
//                if (i == size - 1) {
//                    valMap.put(property, "t." + property +"}}");
//                    continue;
//                }
                valMap.put(property, "t." + property);
            }
            // 表尾
            String lastProperty = EnumForSalaryArchivesHeader.LAST_HEADER.getProperty();
            colEntity = new ExcelExportEntity(EnumForSalaryArchivesHeader.LAST_HEADER.getLabel(), lastProperty);
            colEntity.setNeedMerge(true);
            colList.add(colEntity);
            valMap.put(lastProperty, "t." + lastProperty + "}}");

            list.add(valMap);
            ExportParams exportParams = new ExportParams();
            exportParams.setSheetName("数据");
            exportParams.setStyle(MyExcelExportStyleConfig.class);
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, colList,
                    list);
            String path = request.getSession().getServletContext().getRealPath("/");
            String fileName = path + UUID.randomUUID().toString() + ".xls";
            fileName = fileName.replaceAll("\\\\", "/");
            log.info("临时文件地址: " + fileName);
            FileOutputStream fos = new FileOutputStream(fileName);
            workbook.write(fos);
            fos.close();
            //ClassPathResource classPathResource = new ClassPathResource(fileName);
            Map<String, Object> map = Maps.newHashMap();
            if (isData) {
                SalaryArchivesPageParam archivesPageParam = new SalaryArchivesPageParam();
                archivesPageParam.setPagesize(Integer.MAX_VALUE);
                Map<String, Object> salaryArchivesMap = salaryArchivesService.pageList(archivesPageParam);
                if (salaryArchivesMap.containsKey("data")) {
                    DsResultResponse data = (DsResultResponse) salaryArchivesMap.get("data");
                    JSONArray format = JSONUtils.format(data.getDatas());
                    map.put("list", format);
                } else {
                    map.put("list", Lists.newArrayList());
                }
            } else {
                map.put("list", Lists.newArrayList());
            }
            File deleteFile = new File(fileName);
            TemplateExportParams result = new TemplateExportParams(deleteFile.getPath());
            modelMap.put(TemplateExcelConstants.FILE_NAME, "薪资档案");
            modelMap.put(TemplateExcelConstants.PARAMS, result);
            modelMap.put(TemplateExcelConstants.MAP_DATA, map);
            PoiBaseView.render(modelMap, request, response,
                    TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);

            if (deleteFile.exists()) {
                log.info(deleteFile.delete() ? "临时文件已删除" : "临时文件删除失败");
            } else {
                log.error("无临时文件");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public R importSalaryArchives(MultipartFile file) throws IOException, CannotCompileException, NotFoundException {
        if (file.isEmpty()) {
            return R.error(messageSourceHandler.getMessage("file.nonSelect", null));
        }

        ImportParams params = new ImportParams();
        params.setTitleRows(0);
        params.setHeadRows(1);

        SalaryProjectParam salaryProjectParam = new SalaryProjectParam();
        salaryProjectParam.setAttribute(SalaryProjectDict.FIXED.getId());
        List<Map<String, Object>> projectList = salaryProjectDao.getProjectList(salaryProjectParam);
        projectList.sort(Comparator.comparing(e -> Integer.parseInt(e.get("sortNo").toString())));

        // 表头
        List<CustomizedColumnVO> customizedColumnVOList = Lists.newArrayList();
        CustomizedColumnVO customizedColumnVO;
        LinkedHashMap<String, String> propertyToLabel = EnumForSalaryArchivesHeader.getPropertyToLabel();
        for (Map.Entry<String, String> stringStringEntry : propertyToLabel.entrySet()) {
            customizedColumnVO = new CustomizedColumnVO();
            String property = stringStringEntry.getKey();
            String label = stringStringEntry.getValue();
            customizedColumnVO.setProperty(property);
            customizedColumnVO.setName(label);
            customizedColumnVOList.add(customizedColumnVO);
        }
        // 表中
        List<String> propertyMiddleList = Lists.newArrayList();
        for (Map<String, Object> map : projectList) {
            customizedColumnVO = new CustomizedColumnVO();
            String label = map.get("label").toString();
            String property = map.get("property").toString();
            customizedColumnVO.setProperty(property);
            customizedColumnVO.setName(label);
            customizedColumnVOList.add(customizedColumnVO);
            propertyMiddleList.add(property);
        }
        // 表尾
        String lastProperty = EnumForSalaryArchivesHeader.LAST_HEADER.getProperty();
        String lastLabel = EnumForSalaryArchivesHeader.LAST_HEADER.getLabel();
        customizedColumnVO = new CustomizedColumnVO();
        customizedColumnVO.setProperty(lastProperty);
        customizedColumnVO.setName(lastLabel);
        customizedColumnVOList.add(customizedColumnVO);

        // 检验表的是否合法
        String[] importFields = customizedColumnVOList
                .stream()
                .map(CustomizedColumnVO::getName).toArray(String[]::new);
        params.setImportFields(importFields);

        Class<?> salaryArchivesClass = EasyPoiDynamicGenerationClassUtil.generatePrototypeClass(customizedColumnVOList);

        List<?> salaryArchivesList;
        try {
            salaryArchivesList = ExcelImportUtil.importExcel(file.getInputStream(), salaryArchivesClass, params);
        } catch (Exception e) {
            return R.error(messageSourceHandler.getMessage("file.upload.error", null));
        }
        String salaryArchivesListToString = JSON.toJSONString(salaryArchivesList);
        JSONArray jsonArray = JSON.parseArray(salaryArchivesListToString);
        jsonArray.removeIf(e->{
            JSONObject j = (JSONObject)e;
            return j.size()==0;
        });
        // 需验证数据合法性
//        String deptName = EnumForSalaryArchivesHeader.FIRST_HEADER.getProperty();
        String employeeCode = EnumForSalaryArchivesHeader.SECOND_HEADER.getProperty();
        String effectiveDate = EnumForSalaryArchivesHeader.LAST_HEADER.getProperty();
        Map<String, Object> emptyMap = Maps.newHashMap();
        // 找出数据库中已生成的薪资档案
        List<SalaryArchivesDO> salaryArchivesListInDataSource = salaryArchivesDao.list(emptyMap);
        List<Long> employeeIdListInDataSource = salaryArchivesListInDataSource
                .stream()
                .map(SalaryArchivesDO::getEmployeeId)
                .collect(Collectors.toList());

        // XXX 这里查出了所有员工与部门信息 可以优化
        List<EmployeeInfoDO> employeeInfoDOList = employeeInfoService.list(emptyMap);
//        List<DeptDO> deptDOList = deptService.list(emptyMap);
        Map<String, EmployeeInfoDO> codeToEmployeeDO = employeeInfoDOList
                .stream()
                .collect(Collectors.toMap(EmployeeInfoDO::getEmployeeCode, v -> v, (v1, v2) -> v1));
//        Map<String, DeptDO> nameToDeptDO = deptDOList
//                .stream()
//                .collect(Collectors.toMap(DeptDO::getName, v -> v,(v1,v2)->v1));
        SalaryArchivesDO salaryArchivesDO;
        List<SalaryArchivesDO> salaryArchivesDOList = Lists.newArrayList();
        List<String> errorList = Lists.newArrayList();
        JSONObject jObject;
        JSONArray jArray;
        for (Object o : jsonArray) {
            JSONObject jsonObject = (JSONObject) o;
//            String dept = jsonObject.getString(deptName);
            String employee = jsonObject.getString(employeeCode);
            String effective = jsonObject.getString(effectiveDate);
            if(effective==null){
                return R.error(messageSourceHandler.getMessage("hr.salary.archives.timeIsEmpty", null));
            }
            if (/*dept == null || */employee == null || effectiveDate ==null) {
                continue;
            }
            if (codeToEmployeeDO.containsKey(employee)) {
                salaryArchivesDO = new SalaryArchivesDO();
                EmployeeInfoDO employeeInfoDO = codeToEmployeeDO.get(employee);
                if (employeeIdListInDataSource.contains(employeeInfoDO.getId())) {
                    String employeeName = employeeInfoDO.getEmployeeName();
                    String[] args = {employeeName};
                    return R.error(messageSourceHandler.getMessage("hr.salary.archives.isExist", args));
                }
                salaryArchivesDO.setEmployeeId(employeeInfoDO.getId());
                salaryArchivesDO.setDeptId(employeeInfoDO.getDeptId());
                salaryArchivesDO.setEmployeeName(employeeInfoDO.getEmployeeName());
                jArray = new JSONArray();
                for (String s : propertyMiddleList) {
                    String string = jsonObject.getString(s);
                    if (string != null) {
                        jObject = new JSONObject();
                        jObject.put("property", s);
                        jObject.put("amount", NumberUtils.isNumber(string)?string:0);
                        jArray.add(jObject);
                    }
                }

                Date effectiveDateSource = DateFormatUtil.getDateByParttern(effective, DateFormatUtil.DATE_PATTERN_YMD);
                if(effectiveDateSource==null){
                    return R.error(messageSourceHandler.getMessage("hr.salary.archives.timeIsEmpty", null));
                }
                salaryArchivesDO.setEffectiveDate(effectiveDateSource);

                if (jArray.size() > 0) {
                    salaryArchivesDO.setSalaryProjectJson(jArray.toJSONString());
                }
                salaryArchivesDOList.add(salaryArchivesDO);
            }else {
                errorList.add(employee);
            }

        }
        if (errorList.size() > 0) {
            String collect = String.join(",", errorList);
            String[]args = {"工号"+collect};
            return R.error(messageSourceHandler.getMessage("hr.salary.archives.isEmpty", args));
        }
        if (salaryArchivesDOList.size() > 0) {
            salaryArchivesService.batchInsert(salaryArchivesDOList);
            // 保存第一次薪资记录
//            List<SalaryChangeDO> salaryChangeDOList = Lists.newArrayList();
//            SalaryChangeDO salaryChangeDO;
//            for (SalaryArchivesDO archivesDO : salaryArchivesDOList) {
//                salaryChangeDO = new SalaryChangeDO();
//                BeanUtils.copyProperties(archivesDO,salaryChangeDO);
//                salaryChangeDO.setId(null);
//                salaryChangeDOList.add(salaryChangeDO);
//            }
//            salaryChangeDao.batchInsert(salaryChangeDOList);
            return R.ok();
        }
        return R.error();
    }

    @Override
    public void downLoadTax(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap, boolean isData, String monthDate) {
        try {
            List<ExcelExportEntity> colList = new ArrayList<>();
            SalaryProjectParam salaryProjectParam = new SalaryProjectParam();
            salaryProjectParam.setAttribute(SalaryProjectDict.CHANGE.getId());
            List<Map<String, Object>> projectList = salaryProjectDao.getProjectList(salaryProjectParam);
            // 变动项里以GE_SHUI_ 开头的项目
            List<Map<String, Object>> taxProjectList = projectList
                    .stream()
                    .filter(e -> e.get("property").toString().startsWith("GE_SHUI_"))
                    .sorted(Comparator.comparing(e -> Integer.parseInt(e.get("sortNo").toString())))
                    .collect(Collectors.toList());
            ExcelExportEntity colEntity;
            List<Map<String, Object>> list = Lists.newArrayList();
            Map<String, Object> valMap = Maps.newHashMap();

            // 表头
            LinkedHashMap<String, String> propertyToLabel = EnumForSalaryProjectHeader.getPropertyToLabel();
            boolean isFirst = true;
            for (Map.Entry<String, String> stringStringEntry : propertyToLabel.entrySet()) {
                String property = stringStringEntry.getKey();
                colEntity = new ExcelExportEntity(stringStringEntry.getValue(), property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
                if (isFirst) {
                    valMap.put(stringStringEntry.getKey(), "{{$fe:list t." + stringStringEntry.getKey());
                    isFirst = false;
                    continue;
                }
                valMap.put(property, "t." + property);
            }

            // 表中
            int size = taxProjectList.size();
            for (int i = 0; i < size; i++) {
                Map<String, Object> map = taxProjectList.get(i);
                String label = map.get("label").toString();
                String property = map.get("property").toString();
                colEntity = new ExcelExportEntity(label, property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
//                if (i == 0) {
//                    valMap.put(property, "{{$fe:list t." + property);
//                    continue;
//                }
                // 最后一个表尾
                if (i == size - 1) {
                    valMap.put(property, "t." + property + "}}");
                    continue;
                }
                valMap.put(property, "t." + property);
            }

            list.add(valMap);
            ExportParams exportParams = new ExportParams();
            exportParams.setSheetName("数据");
            exportParams.setStyle(MyExcelExportStyleConfig.class);
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, colList,
                    list);
            String path = request.getSession().getServletContext().getRealPath("/");
            String fileName = path + UUID.randomUUID().toString() + ".xls";
            fileName = fileName.replaceAll("\\\\", "/");
            log.info("临时文件地址: " + fileName);
            FileOutputStream fos = new FileOutputStream(fileName);
            workbook.write(fos);
            fos.close();
//            ClassPathResource classPathResource = new ClassPathResource(fileName);
            Map<String, Object> map = Maps.newHashMap();
            if (isData) {
                SalaryAccountingPageParam salaryAccountingPageParam = new SalaryAccountingPageParam();
                if (StringUtils.isNoneEmpty(monthDate)) {
                    salaryAccountingPageParam.setMonthDate(monthDate);
                }

                salaryAccountingPageParam.setPagesize(Integer.MAX_VALUE);
                Map<String, Object> salaryAccountingMap = salaryAccountingService.pageList(salaryAccountingPageParam);
                if (salaryAccountingMap.containsKey("data")) {
                    DsResultResponse data = (DsResultResponse) salaryAccountingMap.get("data");
                    JSONArray format = JSONUtils.format(data.getDatas());
                    map.put("list", format);
                } else {
                    map.put("list", Lists.newArrayList());
                }
            } else {
                map.put("list", Lists.newArrayList());
            }

            File deleteFile = new File(fileName);
            TemplateExportParams result = new TemplateExportParams(deleteFile.getPath());
            modelMap.put(TemplateExcelConstants.FILE_NAME, "个税");
            modelMap.put(TemplateExcelConstants.PARAMS, result);
            modelMap.put(TemplateExcelConstants.MAP_DATA, map);
            PoiBaseView.render(modelMap, request, response,
                    TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);
            if (deleteFile.exists()) {
                log.info(deleteFile.delete() ? "临时文件已删除" : "临时文件删除失败");
            } else {
                log.error("无临时文件");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public R importTax(MultipartFile file, String monthDate) throws IOException, CannotCompileException, NotFoundException {
        if (file.isEmpty()) {
            return R.error(messageSourceHandler.getMessage("file.nonSelect", null));
        }

        ImportParams params = new ImportParams();
        params.setTitleRows(0);
        params.setHeadRows(1);

        SalaryProjectParam salaryProjectParam = new SalaryProjectParam();
        salaryProjectParam.setAttribute(SalaryProjectDict.CHANGE.getId());
        List<Map<String, Object>> projectList = salaryProjectDao.getProjectList(salaryProjectParam);
        // 变动项里以GE_SHUI_ 开头的项目
        List<Map<String, Object>> taxProjectList = projectList
                .stream()
                .filter(e -> e.get("property").toString().startsWith("GE_SHUI_"))
                .sorted(Comparator.comparing(e -> Integer.parseInt(e.get("sortNo").toString())))
                .collect(Collectors.toList());
        // 表头
        List<CustomizedColumnVO> customizedColumnVOList = Lists.newArrayList();
        CustomizedColumnVO customizedColumnVO;
        LinkedHashMap<String, String> propertyToLabel = EnumForSalaryProjectHeader.getPropertyToLabel();
        for (Map.Entry<String, String> stringStringEntry : propertyToLabel.entrySet()) {
            customizedColumnVO = new CustomizedColumnVO();
            String property = stringStringEntry.getKey();
            String label = stringStringEntry.getValue();
            customizedColumnVO.setProperty(property);
            customizedColumnVO.setName(label);
            customizedColumnVOList.add(customizedColumnVO);
        }
        // 表尾
        List<String> propertyLastList = Lists.newArrayList();
        for (Map<String, Object> map : taxProjectList) {
            customizedColumnVO = new CustomizedColumnVO();
            String label = map.get("label").toString();
            String property = map.get("property").toString();
            customizedColumnVO.setProperty(property);
            customizedColumnVO.setName(label);
            customizedColumnVOList.add(customizedColumnVO);
            propertyLastList.add(property);
        }


        // 检验表的是否合法
        String[] importFields = customizedColumnVOList
                .stream()
                .map(CustomizedColumnVO::getName).toArray(String[]::new);
        params.setImportFields(importFields);

        Class<?> salaryArchivesClass = EasyPoiDynamicGenerationClassUtil.generatePrototypeClass(customizedColumnVOList);

        List<?> salaryArchivesList;
        try {
            salaryArchivesList = ExcelImportUtil.importExcel(file.getInputStream(), salaryArchivesClass, params);
        } catch (Exception e) {
            return R.error(messageSourceHandler.getMessage("file.upload.error", null));
        }
        String salaryArchivesListToString = JSON.toJSONString(salaryArchivesList);
        JSONArray jsonArray = JSON.parseArray(salaryArchivesListToString);
        jsonArray.removeIf(e->{
            JSONObject j = (JSONObject)e;
            return j.size()==0;
        });

        // 需验证数据合法性
//        String deptName = EnumForSalaryArchivesHeader.FIRST_HEADER.getProperty();
        String idNumber = EnumForSalaryProjectHeader.THIRD_HEADER.getProperty();
        String monthDateEnum = EnumForSalaryProjectHeader.SECOND_HEADER.getProperty();

        Map<String, Object> emptyMap = Maps.newHashMap();
        // XXX 这里查出了所有员工与部门信息 可以优化
        List<EmployeeInfoDO> employeeInfoDOList = employeeInfoService.list(emptyMap);


        //        List<DeptDO> deptDOList = deptService.list(emptyMap);
        Map<String, EmployeeInfoDO> idNumberToEmployeeDO = employeeInfoDOList
                .stream()
                .collect(Collectors.toMap(EmployeeInfoDO::getIdNumber, v -> v, (v1, v2) -> v1));
//        Map<String, DeptDO> nameToDeptDO = deptDOList
//                .stream()
//                .collect(Collectors.toMap(DeptDO::getName, v -> v,(v1,v2)->v1));
        List<SalaryAccountingDO> salaryAccountingDOList = Lists.newArrayList();
        List<String> errorList = Lists.newArrayList();
        JSONObject jObject;
        JSONArray jArray;
        List<SalaryAccountingDO> salaryAccountingInDataSource = Lists.newArrayList();
        for (Object o : jsonArray) {
            JSONObject jsonObject = (JSONObject) o;
//            String dept = jsonObject.getString(deptName);
            String employee = jsonObject.getString(idNumber);
            if (/*dept == null || */employee == null) {
                continue;
            }
            String date = jsonObject.getString(monthDateEnum);
            if(StringUtils.isBlank(date)){
                return R.error(messageSourceHandler.getMessage("hr.salary.archives.timeIsEmpty", null));
            }
            // 找出数据库中已生成的薪资数据
            if (salaryAccountingInDataSource.size() == 0) {
                emptyMap.put("monthDateSub", date.substring(0, 7));
                salaryAccountingInDataSource.addAll(salaryAccountingService.list(emptyMap));
            }
            if (salaryAccountingInDataSource.size() > 0) {
                // 若以审核则不能进行导入
                if (Objects.equals(salaryAccountingInDataSource.get(0).getAuditSign(), AuditStatusDict.OK_AUDIT.getId())) {
                    String[] args = {date};
                    return R.error(messageSourceHandler.getMessage("hr.salary.accounting.isAudit", args));
                }

                Map<Long, SalaryAccountingDO> accountingMapInDataSource = salaryAccountingInDataSource
                        .stream()
                        .collect(Collectors.toMap(SalaryAccountingDO::getEmployeeId, e -> e));

                if (idNumberToEmployeeDO.containsKey(employee)) {
                    EmployeeInfoDO employeeInfoDO = idNumberToEmployeeDO.get(employee);
                    if (employeeInfoDO == null) {
                        String[] args = {employee};
                        return R.error(messageSourceHandler.getMessage("hr.salary.accounting.userIsEmpty", args));
                    }
                    if (!accountingMapInDataSource.containsKey(employeeInfoDO.getId())) {
                        String[] args = {employeeInfoDO.getEmployeeName()};
                        return R.error(messageSourceHandler.getMessage("hr.salary.accounting.userNotInAccounting", args));
                    }
                    SalaryAccountingDO salaryAccountingDO = accountingMapInDataSource.get(employeeInfoDO.getId());
                    String salaryChangeJson = salaryAccountingDO.getSalaryChangeJson();
                    if (salaryChangeJson != null) {
                        jArray = JSON.parseArray(salaryChangeJson);
                        if (jArray.size() > 0) {
                            for (String property : propertyLastList) {
                                boolean isExist = false;
                                String amount = jsonObject.getString(property);
                                for (Object o1 : jArray) {
                                    JSONObject jsonObject1 = (JSONObject) o1;
                                    if (Objects.equals(jsonObject1.getString("property"),property)) {
                                        isExist  = true;
                                        jsonObject1.put("amount", amount);
                                    }
                                }
                                if(!isExist){
                                    jObject = new JSONObject();
                                    jObject.put("property", property);
                                    jObject.put("amount", NumberUtils.isNumber(amount)?amount:0);
                                    jArray.add(jObject);
                                }
                            }

                        }

                    } else {
                        jArray = new JSONArray();
                        for (String s : propertyLastList) {
                            String string = jsonObject.getString(s);
                            if (string != null) {
                                jObject = new JSONObject();
                                jObject.put("property", s);
                                jObject.put("amount", NumberUtils.isNumber(string)?string:0);
                                jArray.add(jObject);
                            }
                        }
                    }

                    if (jArray.size() > 0) {
                        salaryAccountingDO.setSalaryChangeJson(jArray.toJSONString());
                    }
                    salaryAccountingDOList.add(salaryAccountingDO);
                }else {
                    errorList.add(employee);
                }
            } else {
                String[] args = {monthDate};
                return R.error(messageSourceHandler.getMessage("hr.salary.accounting.isEmpty", args));
            }
        }
        if (errorList.size() > 0) {
            String collect = String.join(",", errorList);
            String[]args = {"身份证号"+collect};
            return R.error(messageSourceHandler.getMessage("hr.salary.archives.isEmpty", args));
        }

        if (salaryAccountingDOList.size() > 0) {
            salaryAccountingDao.batchUpdate(salaryAccountingDOList);
            return R.ok();
        }
       return R.error();
    }

    @Override
    public void downLoadSocialSecurity(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap,
                                       boolean isData, String monthDate) {
        try {
            List<ExcelExportEntity> colList = new ArrayList<>();
            SalaryProjectParam salaryProjectParam = new SalaryProjectParam();
            salaryProjectParam.setAttribute(SalaryProjectDict.CHANGE.getId());
            List<Map<String, Object>> projectList = salaryProjectDao.getProjectList(salaryProjectParam);
            // 变动项里以SHE_BAO_ 开头的项目
            List<Map<String, Object>> taxProjectList = projectList
                    .stream()
                    .filter(e -> e.get("property").toString().startsWith("SHE_BAO_"))
                    .sorted(Comparator.comparing(e -> Integer.parseInt(e.get("sortNo").toString())))
                    .collect(Collectors.toList());
            ExcelExportEntity colEntity;
            List<Map<String, Object>> list = Lists.newArrayList();
            Map<String, Object> valMap = Maps.newHashMap();

            // 表头
            LinkedHashMap<String, String> propertyToLabel = EnumForSalaryProjectHeader.getPropertyToLabel();
            boolean isFirst = true;
            for (Map.Entry<String, String> stringStringEntry : propertyToLabel.entrySet()) {
                String property = stringStringEntry.getKey();
                colEntity = new ExcelExportEntity(stringStringEntry.getValue(), property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
                if (isFirst) {
                    valMap.put(stringStringEntry.getKey(), "{{$fe:list t." + stringStringEntry.getKey());
                    isFirst = false;
                    continue;
                }
                valMap.put(property, "t." + property);
            }

            // 表中
            int size = taxProjectList.size();
            for (int i = 0; i < size; i++) {
                Map<String, Object> map = taxProjectList.get(i);
                String label = map.get("label").toString();
                String property = map.get("property").toString();
                colEntity = new ExcelExportEntity(label, property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
//                if (i == 0) {
//                    valMap.put(property, "{{$fe:list t." + property);
//                    continue;
//                }
                // 最后一个表尾
                if (i == size - 1) {
                    valMap.put(property, "t." + property + "}}");
                    continue;
                }
                valMap.put(property, "t." + property);
            }

            list.add(valMap);
            ExportParams exportParams = new ExportParams();
            exportParams.setSheetName("数据");
            exportParams.setStyle(MyExcelExportStyleConfig.class);
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, colList,
                    list);
            String path = request.getSession().getServletContext().getRealPath("/");
            String fileName = path + UUID.randomUUID().toString() + ".xls";
            fileName = fileName.replaceAll("\\\\", "/");
            log.info("临时文件地址: " + fileName);
            FileOutputStream fos = new FileOutputStream(fileName);
            workbook.write(fos);
            fos.close();
//            ClassPathResource classPathResource = new ClassPathResource(fileName);
            Map<String, Object> map = Maps.newHashMap();
            if (isData) {
                SalaryAccountingPageParam salaryAccountingPageParam = new SalaryAccountingPageParam();
                if (StringUtils.isNoneEmpty(monthDate)) {
                    salaryAccountingPageParam.setMonthDate(monthDate);
                }

                salaryAccountingPageParam.setPagesize(Integer.MAX_VALUE);
                Map<String, Object> salaryAccountingMap = salaryAccountingService.pageList(salaryAccountingPageParam);
                if (salaryAccountingMap.containsKey("data")) {
                    DsResultResponse data = (DsResultResponse) salaryAccountingMap.get("data");
                    JSONArray format = JSONUtils.format(data.getDatas());
                    map.put("list", format);
                } else {
                    map.put("list", Lists.newArrayList());
                }
            } else {
                map.put("list", Lists.newArrayList());
            }

            File deleteFile = new File(fileName);
            TemplateExportParams result = new TemplateExportParams(deleteFile.getPath());
            modelMap.put(TemplateExcelConstants.FILE_NAME, "社保");
            modelMap.put(TemplateExcelConstants.PARAMS, result);
            modelMap.put(TemplateExcelConstants.MAP_DATA, map);
            PoiBaseView.render(modelMap, request, response,
                    TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);
            if (deleteFile.exists()) {
                log.info(deleteFile.delete() ? "临时文件已删除" : "临时文件删除失败");
            } else {
                log.error("无临时文件");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public R importSocialSecurity(MultipartFile file, String monthDate) throws
            IOException, CannotCompileException, NotFoundException {
        if (file.isEmpty()) {
            return R.error(messageSourceHandler.getMessage("file.nonSelect", null));
        }

        ImportParams params = new ImportParams();
        params.setTitleRows(0);
        params.setHeadRows(1);

        SalaryProjectParam salaryProjectParam = new SalaryProjectParam();
        salaryProjectParam.setAttribute(SalaryProjectDict.CHANGE.getId());
        List<Map<String, Object>> projectList = salaryProjectDao.getProjectList(salaryProjectParam);
        // 变动项里以SHE_BAO_ 开头的项目
        List<Map<String, Object>> taxProjectList = projectList
                .stream()
                .filter(e -> e.get("property").toString().startsWith("SHE_BAO_"))
                .sorted(Comparator.comparing(e -> Integer.parseInt(e.get("sortNo").toString())))
                .collect(Collectors.toList());
        // 表头
        List<CustomizedColumnVO> customizedColumnVOList = Lists.newArrayList();
        CustomizedColumnVO customizedColumnVO;
        LinkedHashMap<String, String> propertyToLabel = EnumForSalaryProjectHeader.getPropertyToLabel();
        for (Map.Entry<String, String> stringStringEntry : propertyToLabel.entrySet()) {
            customizedColumnVO = new CustomizedColumnVO();
            String property = stringStringEntry.getKey();
            String label = stringStringEntry.getValue();
            customizedColumnVO.setProperty(property);
            customizedColumnVO.setName(label);
            customizedColumnVOList.add(customizedColumnVO);
        }
        // 表尾
        List<String> propertyLastList = Lists.newArrayList();
        for (Map<String, Object> map : taxProjectList) {
            customizedColumnVO = new CustomizedColumnVO();
            String label = map.get("label").toString();
            String property = map.get("property").toString();
            customizedColumnVO.setProperty(property);
            customizedColumnVO.setName(label);
            customizedColumnVOList.add(customizedColumnVO);
            propertyLastList.add(property);
        }


        // 检验表的是否合法
        String[] importFields = customizedColumnVOList
                .stream()
                .map(CustomizedColumnVO::getName).toArray(String[]::new);
        params.setImportFields(importFields);

        Class<?> salaryArchivesClass = EasyPoiDynamicGenerationClassUtil.generatePrototypeClass(customizedColumnVOList);

        List<?> salaryArchivesList;
        try {
            salaryArchivesList = ExcelImportUtil.importExcel(file.getInputStream(), salaryArchivesClass, params);
        } catch (Exception e) {
            return R.error(messageSourceHandler.getMessage("file.upload.error", null));
        }
        String salaryArchivesListToString = JSON.toJSONString(salaryArchivesList);
        JSONArray jsonArray = JSON.parseArray(salaryArchivesListToString);
        jsonArray.removeIf(e->{
            JSONObject j = (JSONObject)e;
            return j.size()==0;
        });
        // 需验证数据合法性
//        String deptName = EnumForSalaryArchivesHeader.FIRST_HEADER.getProperty();
        String idNumber = EnumForSalaryProjectHeader.THIRD_HEADER.getProperty();
        String monthDateEnum = EnumForSalaryProjectHeader.SECOND_HEADER.getProperty();
        Map<String, Object> emptyMap = Maps.newHashMap();
        // XXX 这里查出了所有员工与部门信息 可以优化
        List<EmployeeInfoDO> employeeInfoDOList = employeeInfoService.list(emptyMap);


        //        List<DeptDO> deptDOList = deptService.list(emptyMap);
        Map<String, EmployeeInfoDO> idNumberToEmployeeDO = employeeInfoDOList
                .stream()
                .collect(Collectors.toMap(EmployeeInfoDO::getIdNumber, v -> v, (v1, v2) -> v1));
//        Map<String, DeptDO> nameToDeptDO = deptDOList
//                .stream()
//                .collect(Collectors.toMap(DeptDO::getName, v -> v,(v1,v2)->v1));
        List<SalaryAccountingDO> salaryAccountingDOList = Lists.newArrayList();
        List<String> errorList = Lists.newArrayList();
        JSONObject jObject;
        JSONArray jArray;
        List<SalaryAccountingDO> salaryAccountingInDataSource = Lists.newArrayList();
        for (Object o : jsonArray) {
            JSONObject jsonObject = (JSONObject) o;
//            String dept = jsonObject.getString(deptName);
            String employee = jsonObject.getString(idNumber);
            if (/*dept == null || */employee == null) {
                continue;
            }
            String date = jsonObject.getString(monthDateEnum);
            if(StringUtils.isBlank(date)){
                return R.error(messageSourceHandler.getMessage("hr.salary.archives.timeIsEmpty", null));
            }
            // 找出数据库中已生成的薪资数据
            if (salaryAccountingInDataSource.size() == 0) {
                emptyMap.put("monthDateSub", date.substring(0, 7));
                salaryAccountingInDataSource.addAll(salaryAccountingService.list(emptyMap));
            }
            if (salaryAccountingInDataSource.size() > 0) {
                // 若以审核则不能进行导入
                if (Objects.equals(salaryAccountingInDataSource.get(0).getAuditSign(), AuditStatusDict.OK_AUDIT.getId())) {
                    String[] args = {date};
                    return R.error(messageSourceHandler.getMessage("hr.salary.accounting.isAudit", args));
                }

                Map<Long, SalaryAccountingDO> accountingMapInDataSource = salaryAccountingInDataSource
                        .stream()
                        .collect(Collectors.toMap(SalaryAccountingDO::getEmployeeId, e -> e));

                if (idNumberToEmployeeDO.containsKey(employee)) {
                    EmployeeInfoDO employeeInfoDO = idNumberToEmployeeDO.get(employee);
                    if (employeeInfoDO == null) {
                        String[] args = {employee};
                        return R.error(messageSourceHandler.getMessage("hr.salary.accounting.userIsEmpty", args));
                    }
                    if (!accountingMapInDataSource.containsKey(employeeInfoDO.getId())) {
                        String[] args = {employeeInfoDO.getEmployeeName()};
                        return R.error(messageSourceHandler.getMessage("hr.salary.accounting.userNotInAccounting", args));
                    }
                    SalaryAccountingDO salaryAccountingDO = accountingMapInDataSource.get(employeeInfoDO.getId());
                    String salaryChangeJson = salaryAccountingDO.getSalaryChangeJson();
                    if (salaryChangeJson != null) {
                        jArray = JSON.parseArray(salaryChangeJson);
                        if (jArray.size() > 0) {
                            for (String property : propertyLastList) {
                                boolean isExist = false;
                                String amount = jsonObject.getString(property);
                                for (Object o1 : jArray) {
                                    JSONObject jsonObject1 = (JSONObject) o1;
                                    if (Objects.equals(jsonObject1.getString("property"),property)) {
                                        isExist  = true;
                                        jsonObject1.put("amount", amount);
                                    }
                                }
                                if(!isExist){
                                    jObject = new JSONObject();
                                    jObject.put("property", property);
                                    jObject.put("amount", NumberUtils.isNumber(amount)?amount:0);
                                    jArray.add(jObject);
                                }
                            }

                        }

                    } else {
                        jArray = new JSONArray();
                        for (String s : propertyLastList) {
                            String string = jsonObject.getString(s);
                            if (string != null) {
                                jObject = new JSONObject();
                                jObject.put("property", s);
                                jObject.put("amount", NumberUtils.isNumber(string)?string:0);
                                jArray.add(jObject);
                            }
                        }
                    }

                    if (jArray.size() > 0) {
                        salaryAccountingDO.setSalaryChangeJson(jArray.toJSONString());
                    }
                    salaryAccountingDOList.add(salaryAccountingDO);
                } else {
                    errorList.add(employee);
                }
            } else {
                String[] args = {monthDate};
                return R.error(messageSourceHandler.getMessage("hr.salary.accounting.isEmpty", args));
            }
        }
        if (errorList.size() > 0) {
            String collect = String.join(",", errorList);
            String[]args = {"身份证号"+collect};
            return R.error(messageSourceHandler.getMessage("hr.salary.archives.isEmpty", args));
        }

        if (salaryAccountingDOList.size() > 0) {
            salaryAccountingDao.batchUpdate(salaryAccountingDOList);
            return R.ok();
        }
        return R.error();

    }

    @Override
    public void downLoadRecord(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap, boolean isData, String monthDate) {
        try {
            List<ExcelExportEntity> colList = new ArrayList<>();
            SalaryProjectParam salaryProjectParam = new SalaryProjectParam();
            salaryProjectParam.setIsShowSalaryAccounting(1);
            List<Map<String, Object>> projectList = salaryProjectDao.getProjectList(salaryProjectParam);
            ExcelExportEntity colEntity;
            List<Map<String, Object>> list = Lists.newArrayList();
            Map<String, Object> valMap = Maps.newHashMap();

            // 表头
            LinkedHashMap<String, String> propertyToLabel = EnumForSalaryProjectHeader.getPropertyToLabel();
            boolean isFirst = true;
            for (Map.Entry<String, String> stringStringEntry : propertyToLabel.entrySet()) {
                String property = stringStringEntry.getKey();
                colEntity = new ExcelExportEntity(stringStringEntry.getValue(), property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
                if (isFirst) {
                    valMap.put(stringStringEntry.getKey(), "{{$fe:list t." + stringStringEntry.getKey());
                    isFirst = false;
                    continue;
                }
                valMap.put(property, "t." + property);
            }

            // 表中
//            int size = projectList.size();
            for (Map<String, Object> map : projectList) {
                String label = map.get("label").toString();
                String property = map.get("property").toString();
                colEntity = new ExcelExportEntity(label, property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
//                if (i == 0) {
//                    valMap.put(property, "{{$fe:list t." + property);
//                    continue;
//                }
                // 最后一个表尾
//                if (i == size - 1) {
//                    valMap.put(property, "t." + property + "}}");
//                    continue;
//                }
                valMap.put(property, "t." + property);
            }
            // 最后一个审核状态
            colEntity = new ExcelExportEntity("审核状态", "auditSignName");
            colEntity.setNeedMerge(true);
            colList.add(colEntity);
            valMap.put("auditSignName", "t.auditSignName}}");

            list.add(valMap);
            ExportParams exportParams = new ExportParams();
            exportParams.setSheetName("数据");
            exportParams.setStyle(MyExcelExportStyleConfig.class);
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, colList,
                    list);
            String path = request.getSession().getServletContext().getRealPath("/");
            String fileName = path + UUID.randomUUID().toString() + ".xls";
            fileName = fileName.replaceAll("\\\\", "/");
            log.info("临时文件地址: " + fileName);
            FileOutputStream fos = new FileOutputStream(fileName);
            workbook.write(fos);
            fos.close();
//            ClassPathResource classPathResource = new ClassPathResource(fileName);
            Map<String, Object> map = Maps.newHashMap();
            if (isData) {
                SalaryAccountingPageParam salaryAccountingPageParam = new SalaryAccountingPageParam();
                if (StringUtils.isNoneEmpty(monthDate)) {
                    salaryAccountingPageParam.setMonthDate(monthDate);
                }

                salaryAccountingPageParam.setPagesize(Integer.MAX_VALUE);
                Map<String, Object> salaryAccountingMap = salaryAccountingService.pageList(salaryAccountingPageParam);
                if (salaryAccountingMap.containsKey("data")) {
                    DsResultResponse data = (DsResultResponse) salaryAccountingMap.get("data");
                    JSONArray format = JSONUtils.format(data.getDatas());
                    map.put("list", format);
                } else {
                    map.put("list", Lists.newArrayList());
                }
            } else {
                map.put("list", Lists.newArrayList());
            }

            File deleteFile = new File(fileName);
            TemplateExportParams result = new TemplateExportParams(deleteFile.getPath());
            modelMap.put(TemplateExcelConstants.FILE_NAME, "薪资记录");
            modelMap.put(TemplateExcelConstants.PARAMS, result);
            modelMap.put(TemplateExcelConstants.MAP_DATA, map);
            PoiBaseView.render(modelMap, request, response,
                    TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);
            if (deleteFile.exists()) {
                log.info(deleteFile.delete() ? "临时文件已删除" : "临时文件删除失败");
            } else {
                log.error("无临时文件");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
